/*************************************************
  Copyright (C) 2020 HanXiaohu. <10199274@qq.com>
  File name: 智能行李箱.ino
  Author： HanXiaohu
  Version: 1.0
  Description: GPRS TXD <-----> D10
             GPRS RXD <-----> D11
             GPS RX  <-----> D3
             GPS TX  <-----> D2
             DHT22   <-----> D12
             FSR     <-----> A0
*************************************************/

#include <SoftwareSerial.h>
#include <TinyGPS.h>
#include "DHT.h"

/*   传感器接口定义   */
#define DHTPIN 12   //DHT22
#define fsrPin 0    //FSR402


/*   温湿度传感器   */
DHT dht(DHTPIN, DHT22);


/*   GPS define   */
TinyGPS gps;
SoftwareSerial gpsSerial(2, 3); // GPS RX, TX


/*   OneNET define   */

//OneNET Studio 服务器地址
const char *server = "218.201.45.7";
//端口号
const int port = 1883;
//设备名称
#define mqtt_devid ""
//产品ID
#define mqtt_pubid ""
//鉴权信息
#define mqtt_password ""
//数据流topic
#define dp_topic "$sys/" mqtt_pubid "/" mqtt_devid "/thing/property/post"


/*   GSM800C Client define   */

// Select your modem:
#define TINY_GSM_MODEM_SIM800

// Set serial for debug console (to the Serial Monitor, default speed 115200)
#define SerialMon Serial

// or Software Serial on Uno, Nano
SoftwareSerial SerialAT(10, 11); // RX, TX

// Define the serial console for debug prints, if needed
#define TINY_GSM_DEBUG SerialMon

// Define how you're planning to connect to the internet
#define TINY_GSM_USE_GPRS true
#define TINY_GSM_USE_WIFI false

#include <TinyGsmClient.h>
#include <PubSubClient.h>

TinyGsm modem(SerialAT);
TinyGsmClient client(modem);
PubSubClient mqtt(client);




void mqttCallback(char* topic, byte* payload, unsigned int len) {
  SerialMon.print(F("Message arrived ["));
  SerialMon.print(topic);
  SerialMon.print(F("]: "));
  SerialMon.write(payload, len);
  SerialMon.println();
}

boolean mqttConnect() {

  char pw_buffer[130];

  SerialMon.print(F("Connecting to "));
  SerialMon.print(server);

  memset(pw_buffer, 0, sizeof(pw_buffer));
  strcpy_P(pw_buffer, PSTR(mqtt_password));
  // authenticate MQTT:
  boolean status = mqtt.connect(mqtt_devid, mqtt_pubid, pw_buffer);

  if (status == false) {
    SerialMon.println(F(" fail"));
    return false;
  }
  SerialMon.println(F(" success"));
  return true;
}


void setup() {

  // Set console baud rate
  SerialMon.begin(115200);
  delay(100);
  SerialMon.println(F("Wait..."));

  // Set GSM module baud rate
  SerialAT.begin(9600);
  delay(100);

  // Restart takes quite some time
  // To skip it, call init() instead of restart()
  SerialMon.println(F("Initializing modem..."));
  modem.restart();
  // modem.init();

  SerialMon.print(F("Modem Info: "));
  SerialMon.println(modem.getModemInfo());

  SerialMon.print(F("Waiting for network..."));
  if (!modem.waitForNetwork()) {
    SerialMon.println(F(" fail"));
    delay(10000);
    return;
  }
  SerialMon.println(F(" success"));

  // GPRS connection parameters are usually set after network registration
  SerialMon.print(F("Connecting to GPRS"));
  if (!modem.gprsConnect("", "", "")) {
    SerialMon.println(F(" fail"));
    delay(10000);
    return;
  }
  SerialMon.println(F(" success"));


  // MQTT Broker setup
  mqtt.setServer(server, port);
  mqtt.setCallback(mqttCallback);

  //温湿度传感器初始化
  dht.begin();
  gpsSerial.begin(9600);
}



/* 定时器计数器 */
unsigned long mqtt_timer = 0;
unsigned long gps_timer = 0;


void sendToOnenet(char *name, float value)
{
  char temp_str[10];
  char msgJson[60];

  dtostrf(value, 3, 1, temp_str);
  memset(msgJson, 0, sizeof(msgJson));
  strcat_P(msgJson, PSTR("{\"id\":\"123\",\"params\":{\""));
  strcat_P(msgJson, name);
  strcat_P(msgJson, PSTR("\":{\"value\":"));
  strcat(msgJson, temp_str);
  strcat_P(msgJson, PSTR("}}}"));
  Serial.println(msgJson);
  Serial.println(strlen(msgJson));
  SerialAT.listen();
  mqtt.publish(dp_topic, msgJson);
}

void sendGpsToOnenet(char *name, float gpsLat, float gpsLon)
{
  char temp_str[12];
  char msgJson[100];

  memset(msgJson, 0, sizeof(msgJson));
  strcat_P(msgJson, PSTR("{\"id\":\"123\",\"params\":{\""));
  strcat_P(msgJson, name);
  strcat_P(msgJson, PSTR("\":{\"value\":{\"Latitude\":"));
  dtostrf(gpsLat, 3, 6, temp_str);
  strcat(msgJson, temp_str);
  strcat_P(msgJson, PSTR(",\"Longitude\":"));
  dtostrf(gpsLon, 3, 6, temp_str);
  strcat(msgJson, temp_str);
  strcat_P(msgJson, PSTR("}}}}"));
  Serial.println(msgJson);
  Serial.println(strlen(msgJson));
  SerialAT.listen();
  mqtt.publish(dp_topic, msgJson);
}

void gpsRun()
{
  bool newData = false;
  float gpsLat, gpsLon;

  if (millis() - gps_timer > 10000L) {
    gpsSerial.listen();
    // For one second we parse GPS data and report some key values
    for (unsigned long start = millis(); millis() - start < 1000;)
    {
      while (gpsSerial.available())
      {
        char c = gpsSerial.read();
        if (gps.encode(c))
          newData = true;
      }
    }

    if (newData)
    {
      unsigned long age;
      gps.f_get_position(&gpsLat, &gpsLon, &age);
      sendGpsToOnenet(PSTR("GeoLocation"), gpsLat, gpsLon);
    }
    gps_timer = millis();
  }
}

void loop() {
  float fsrReading;
  float humi, temp;

  SerialAT.listen();
  if (millis() - mqtt_timer > 10000L) {
    // Reconnect every 10 seconds
    if (!mqtt.connected()) {
      mqttConnect();
    }
    mqtt_timer = millis();
  }

  humi = dht.readHumidity(); //读取湿度
  temp = dht.readTemperature(); //读取温度
  fsrReading = analogRead(fsrPin);//读取压力传感器数据
  sendToOnenet(PSTR("Humidity"), humi);
  sendToOnenet(PSTR("Temperature"), temp);
  sendToOnenet(PSTR("Weight"), fsrReading);
  
  mqtt.loop();

  gpsRun();
  delay(5000);
}
